package me.fenglu.flowable.service;

import me.fenglu.flowable.bean.MyTask;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class MyTaskService {
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    private HistoryService historyService;
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Transactional
    public void startProcess(String processKey, Map<String, Object> variables) {
        runtimeService.startProcessInstanceByKey(processKey, variables);
    }
    
    public List<MyTask> getTasks(String assignee, String type) {
        List<Task> taskList;
        if (type.equals("assignee"))
            taskList = taskService.createTaskQuery().taskCandidateOrAssigned(assignee).active().list();
        else
            taskList = taskService.createTaskQuery().taskCandidateGroup(assignee).active().list();
        List<MyTask> myTaskList = taskList.stream().map(m -> {
            String taskId = m.getId();
            Map<String, Object> variables = taskService.getVariables(taskId);
            MyTask myTask = new MyTask();
            myTask.setId(taskId);
            myTask.setName(m.getName() + "(" + variables.get("employee") + ")");
            myTask.setNrOfHoliday(Integer.valueOf(variables.get("nrOfHoliday").toString()));
            myTask.setUsername((String) variables.get("employee"));
            myTask.setDesc((String) variables.get("desc"));
            myTask.setProcessInstanceId(m.getProcessInstanceId());
            return myTask;
        }).collect(Collectors.toList());
        return myTaskList;
    }
    
    @Transactional
    public void complete(String taskId, boolean approved) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", approved);
        taskService.complete(taskId, variables);
    }
    
    public List<MyTask> getHistoryTasks(String assignee, String type) {
        List<HistoricTaskInstance> taskList1;
        if (type.equals("assignee"))
            taskList1 = historyService.createHistoricTaskInstanceQuery().taskAssignee(assignee).finished().list();
        else
            taskList1 = historyService.createHistoricTaskInstanceQuery().taskCandidateGroup(assignee).finished().list();
        List<MyTask> historyList = taskList1.stream().map(m -> {
            String processInstanceId = m.getProcessInstanceId();
            List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list();
            MyTask myTask = new MyTask();
            myTask.setId(m.getId());
            myTask.setName(m.getName());
            myTask.setProcessInstanceId(processInstanceId);
            variables.stream().forEach(v -> {
                String vName = v.getVariableName();
                Object vValue = v.getValue();
                switch (vName) {
                    case "employee":
                        myTask.setName(m.getName() + "(" + vValue + ")");
                        myTask.setUsername(vValue.toString());
                        break;
                    case "nrOfHoliday":
                        myTask.setNrOfHoliday((int) vValue);
                        break;
                    case "desc":
                        myTask.setDesc(vValue.toString());
                        break;
                    case "approved":
                        myTask.setApproved((boolean) vValue);
                        break;
                }
            });
            return myTask;
        }).collect(Collectors.toList());
        return historyList;
    }
    
    public MyTask getHistoryTask(String processInstanceId) {
        HistoricTaskInstance m = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).unfinished().singleResult();
        List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list();
        MyTask myTask = new MyTask();
        myTask.setId(m.getId());
        myTask.setName(m.getName());
        myTask.setProcessInstanceId(processInstanceId);
        variables.stream().forEach(v -> {
            String vName = v.getVariableName();
            Object vValue = v.getValue();
            switch (vName) {
                case "employee":
                    myTask.setName(m.getName() + "(" + vValue + ")");
                    myTask.setUsername(vValue.toString());
                    break;
                case "nrOfHoliday":
                    myTask.setNrOfHoliday((int) vValue);
                    break;
                case "desc":
                    myTask.setDesc(vValue.toString());
                    break;
                case "approved":
                    myTask.setApproved((boolean) vValue);
                    break;
            }
        });
        return myTask;
    }
    
    public Task getTask(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }
    
    public HistoricProcessInstance getHisPI(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    }
    
    public HistoricTaskInstance getHistoricTaskInstance(String processInstanceId) {
        return historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).unfinished().singleResult();
    }
    
    public BpmnModel getBpmnModel(String processDefinitionId) {
        return repositoryService.getBpmnModel(processDefinitionId);
    }
    
    public List<String> getActiveActivityIds(String executionId) {
        return runtimeService.getActiveActivityIds(executionId);
    }
}
